//
// Copyright (c) 2010 Alex Nesterenko
//

#include "serializesystem/xml/xmlserializesystem.h"
#include "serializesystem/protocol.h"
#include "filesystem/filesysteminterface.h"

#include <cassert>

namespace nane
{
    ////////////////////////////////////////////////////////////////////////////
    void initializeSystem( SerializeSystemInterface** _serializeSystem )
    {
        *_serializeSystem = new XMLSerializeSystem();
        if( *_serializeSystem != NULL
                && (*_serializeSystem)->initialize() == false )
        {
            delete static_cast<XMLSerializeSystem*>( *_serializeSystem );
            *_serializeSystem = NULL;
        }
    }
    ////////////////////////////////////////////////////////////////////////////
    void shutdownSystem( SerializeSystemInterface* _serializeSystem )
    {
        if( _serializeSystem != NULL )
        {
            _serializeSystem->shutdown();
            delete static_cast<XMLSerializeSystem*>( _serializeSystem );
        }
    }
    ////////////////////////////////////////////////////////////////////////////
    void s_startElementHandler( void* _userData, const XML_Char* _name, const XML_Char** _atts )
    {
        Protocol* protocol = static_cast<Protocol*>( _userData );
        protocol->onElementStart( _name );
        while( (*_atts) != NULL )
        {
            protocol->onAttribute( *_atts, *(_atts+1) );
            _atts += 2;
        }
    }
    ////////////////////////////////////////////////////////////////////////////
    void s_endElementHandler( void* _userData, const XML_Char* _name )
    {
        Protocol* protocol = static_cast<Protocol*>( _userData );
        protocol->onElementEnd( _name );
    }
    ////////////////////////////////////////////////////////////////////////////
    XMLSerializeSystem::XMLSerializeSystem()
        : m_parser( NULL )
    {

    }
    ////////////////////////////////////////////////////////////////////////////
    XMLSerializeSystem::~XMLSerializeSystem()
    {
        assert( m_parser == NULL );
    }
    ////////////////////////////////////////////////////////////////////////////
    bool XMLSerializeSystem::initialize()
    {
        assert( m_parser == NULL );
        if( m_parser != NULL )
        {
            shutdown();
        }
        m_parser = XML_ParserCreate( NULL );
        if( m_parser == NULL )
        {
            return false;
        }

        XML_SetElementHandler( m_parser, &s_startElementHandler, &s_endElementHandler );
        return true;
    }
    ////////////////////////////////////////////////////////////////////////////
    void XMLSerializeSystem::shutdown()
    {
        if( m_parser != NULL )
        {
            XML_ParserFree( m_parser );
            m_parser = NULL;
        }
    }
    ////////////////////////////////////////////////////////////////////////////
    bool XMLSerializeSystem::deserialize( InputSeekableInterface* _input, Protocol* _protocol )
    {
        assert( _input != NULL && _protocol != NULL && m_parser != NULL );
        if( _input == NULL || _protocol == NULL || m_parser == NULL )
        {
            return false;
        }

        XML_SetUserData( m_parser, _protocol );

        int32 bufferSize = _input->size();
        void* expatBuffer = XML_GetBuffer( m_parser, bufferSize );
        if( expatBuffer == NULL )
        {
            return false;
        }

        _input->read( static_cast<byte*>( expatBuffer ), bufferSize );

        _protocol->onDocumentStart();

        if( XML_ParseBuffer( m_parser, bufferSize, true ) == 0 )
        {
            return false;
        }

        _protocol->onDocumentEnd();

        return true;
    }
    ////////////////////////////////////////////////////////////////////////////
}   // namespace nane
